﻿/*
/// 
/// Portions Copyright 1999-2004 Carnegie Mellon University.  
/// Portions Copyright 2004 Sun Microsystems, Inc.  
/// Portions Copyright 2004 Mitsubishi Electric Research Laboratories.
/// All Rights Reserved.  Use is subject to license terms.
/// 
/// See the file "license.terms" for information on usage and
/// redistribution of this file, and for a DISCLAIMER OF ALL 
/// WARRANTIES.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Decoder.Search;
using Util.Props;
using System.Diagnostics;
using Common;

namespace Decoder
{
    /// <summary>
    /// An abstract decoder which implements all functionality which is independent of the used decoding-paradigm (pull/push).
    /// </summary>
    public abstract class AbstractDecoder : IResultProducer,IConfigurable
    {
        /// <summary>
        /// The property that defines the name of the search manager to use
        /// </summary>
        [S4Component(type=typeof(Search.ISearchManager))]
        public static String PROP_SEARCH_MANAGER = "searchManager";
        protected ISearchManager searchManager=null;
        /// <summary>
        /// The property that defines the name of the search manager to use
        /// </summary>
        [S4ComponentList(type = typeof(IResultListener))]
        public static String PROP_RESULT_LISTENERS = "resultListeners";
        protected List<IResultListener> resultListeners = new List<IResultListener>();
        /// <summary>
        /// If set to true the used search-manager will be automatically allocated
        ///  in <code>newProperties()</code>.
        /// </summary>
        [S4Boolean(defaultValue = false)]
        public static String AUTO_ALLOCATE = "autoAllocate";
        /// <summary>
        /// If set to <code>false</code> the used search-manager all registered
        /// result listeners will be notified only for final results. Per default
        /// non-final results don't trigger notification, because in most
        /// application the utterance final result will be sufficient.
        /// </summary>
        [S4Boolean(defaultValue = false)]
        public static String FIRE_NON_FINAL_RESULTS = "fireNonFinalResults";
        private Boolean fireNonFinalResults=false;

        private String name;


        public AbstractDecoder() 
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="searchManager"></param>
        /// <param name="fireNonFinalResults"></param>
        /// <param name="autoAllocate"></param>
        /// <param name="resultListeners"></param>
        public AbstractDecoder(ISearchManager searchManager, Boolean fireNonFinalResults, Boolean autoAllocate, List<IResultListener> resultListeners) 
        {
            String name = base.GetType().Name;
            init( name, searchManager, fireNonFinalResults, autoAllocate, resultListeners);        
        }
        /// <summary>
        /// Decode frames until recognition is complete
        /// </summary>
        /// <param name="referenceText">the reference text (or null)</param>
        /// <returns>a result</returns>
        public abstract IResult decode(String referenceText);

        public abstract void newProperties(PropertySheet ps);
        
        private void init(String name,  ISearchManager searchManager, Boolean fireNonFinalResults, Boolean autoAllocate, List<IResultListener> listeners) 
        {
            this.name = name;

            this.searchManager = searchManager;
            this.fireNonFinalResults = fireNonFinalResults;

            if (autoAllocate) {
                searchManager.allocate();
            }

            foreach (IResultListener listener in listeners) 
            {
                addResultListener(listener);
            }
        }


        /// <summary>
        /// Allocate resources necessary for decoding
        /// </summary>
        public void allocate() 
        {
            searchManager.allocate();
        }


        /// <summary>
        /// Deallocate resources
        /// </summary>
        public void deallocate() 
        {
            searchManager.deallocate();
        }

        /// <summary>
        /// Adds a result listener to this recognizer. A result listener is called whenever a new result is generated by the
        /// recognizer. This method can be called in any state.
        /// </summary>
        /// <param name="resultListener"></param>
        public void addResultListener(IResultListener resultListener) 
        {
            resultListeners.Add(resultListener);
        }

        /// <summary>
        /// Removes a previously added result listener. This method can be called in any state.
        /// </summary>
        /// <param name="resultListener">the listener to remove</param>
        public void removeResultListener(IResultListener resultListener) 
        {
            resultListeners.Remove(resultListener);
        }
        /// <summary>
        /// Fires new results as soon as they become available.
        /// </summary>
        /// <param name="result">the new result</param>
        protected void fireResultListeners(IResult result) 
        {
            if (fireNonFinalResults || result.isFinal()) 
            {
                foreach (IResultListener resultListener in resultListeners) 
                {
                    resultListener.newResult(result);
                }
            }
            else 
            {
                Trace.WriteLine("skipping non-final result " + result);
            }
        }

        override  public String ToString() 
        {
            return name;
        }



        void IConfigurable.newProperties(PropertySheet ps)
        {
            init( ps.InstanceName,  
                (ISearchManager) ps.getComponent(PROP_SEARCH_MANAGER), 
                ps.getBoolean(FIRE_NON_FINAL_RESULTS), 
                ps.getBoolean(AUTO_ALLOCATE),
                ps.getComponentList<IResultListener>(PROP_RESULT_LISTENERS)
           );
           newProperties(ps);
        }
    }
}
